<?php
/**
 * a ssh client
 * @author : tom.wang(yulin.wang@qq.com)
 */
class SSHUtil {
	protected $cfg;
	protected $ssh;
	protected $sftp;
	
	/**
	 * construct method
	 */
	public function __construct($cfg = array()) {
		$this->setCfg($cfg);
		$this->connect();
		$this->authenticate();
	}
	
	/**
	 * download a file through scp
	 *
	 * @param string $from : remote file
	 * @param string $to : local file
	 *
	 * @return bool : success true fail false
	 */
	public function download($from, $to) {
		$from = ssh2_sftp_realpath($this->sftp, $from);
		$ret = @ssh2_scp_recv($this->ssh, $from, $to);
		
		return $ret;
	}
	
	/**
	 * upload a file through scp
	 *
	 * @param string $from
	 * @param string $to
	 * @param int $mode
	 *
	 * @return bool
	 */
	public function upload($from, $to, $mode = 0644) {
		$to = ssh2_sftp_realpath($this->sftp, $to);
		$ret = ssh2_scp_send($this->ssh, $from, $to, $mode);
		
		return $ret;
	}
	
	/**
	 * delete a file
	 *
	 * @param string $file
	 *
	 * @return bool
	 */
	public function delete($file) {
		$file = ssh2_sftp_realpath($this->sftp, $file);
		$ret = ssh2_sftp_unlink($this->sftp, $file);
		
		return $ret;
	}
	
	/**
	 * create a directory, similar to mkdir use 'ssh2.sftp://' wrapper
	 *
	 * @param string $dir
	 * @param int $mode
	 *
	 * @return bool
	 */
	public function mkdir($dir, $mode = 0777) {
		$dir = ssh2_sftp_realpath($this->sftp, $dir);
		$ret = @ssh2_sftp_mkdir($this->sftp, $dir, $mode, true);
		
		return $ret;
	}
	
	/**
	 * remove a directory, similar to using rmdir() with the ssh2.sftp:// wrapper
	 *
	 * @param string $dir
	 *
	 * @return bool
	 */
	public function rmdir($dir) {
		$dir = ssh2_sftp_realpath($this->sftp, $dir);
		$ret = @ssh2_sftp_rmdir($this->sftp, $dir);
		
		return $ret;
	}
	
	/**
	 * rename a file or directory
	 *
	 * @param string $from : old name
	 * @param string $to : new name
	 *
	 * @return bool
	 */
	public function rename($from, $to) {
		$from = ssh2_sftp_realpath($this->sftp, $from);
		$to = ssh2_sftp_realpath($this->sftp, $to);
		$ret = ssh2_sftp_rename($this->sftp, $from, $to);
		
		return $ret;
	}
	
	/**
	 * exec a command
	 *
	 * @param string $cmd
	 *
	 * @return string
	 */
	public function exec($cmd) {
		$stream = ssh2_exec($this->ssh, $cmd);
		stream_set_blocking($stream, true);
		$ret = '';
		while ($line = fgets($stream)) {
			flush();
			$ret .= $line;
		}
		
		return $ret;
	}
	
	/**
	 * get support authenticate methods
	 *
	 * @return array : array('none') or array(...)
	 */
//	public function getAuthType() {
//		$types = array();
//		$auth = ssh2_auth_none($this->ssh, $this->cfg['username']);
//		if($auth === true) {
//			$types[] = 'none';
//		} else {
//			$types = $auth;
//		}
//		
//		return $types;
//	}
	
	/**
	 * connect to the ssh server
	 */
	protected function connect() {
		//connect server
		//can set methods and callbacks parameters in ssh2_connect method
		$this->ssh = ssh2_connect($this->cfg['host'], $this->cfg['port']);
		if($this->ssh === false) {
			throw new SSHException(SSHException::SSH_CONNECT_FAIL);
		}
		//check hostkey
		if($this->cfg['hostkey'] != '' && $this->cfg['hostkey'] != ssh2_fingerprint
($this->ssh, $this->cfg['hostkeyflag'])) {
			throw new SSHException(SSHException::SSH_HOSTKEY_FAIL);
		}
		//init sftp
		$this->sftp = ssh2_sftp($this->ssh);
	}
	
	/**
	 * authenticate
	 */
	protected function authenticate() {
		switch($this->cfg['auth_type']) {
			case 'none':
				$ret = ssh2_auth_none($this->ssh, $this->cfg['username']);
				break;
			case 'password':
			default:
				$ret = @ssh2_auth_password($this->ssh, $this->cfg['username'], $this->cfg['password']);
				break;
		}
		
		//when auth_type is none and authenticate fail, it will return an array
		if($ret !== true) {
			throw new SSHException(SSHException::SSH_AUTHENTICATE_FAIL);
		}
	}
	
	/**
	 * set config
	 *
	 * @param array $cfg
	 */
	protected function setCfg($cfg) {
		$this->cfg = require FRAMEWORK_SSH_ROOT . 'config.php';
		
		foreach($cfg as $key => $val) {
			if(array_key_exists($key, $this->cfg)) $this->cfg[$key] = $val;
		}
	}
}
?>